import { Injectable, HttpException, HttpStatus, NotFoundException } from '@nestjs/common'
import { InjectRepository, InjectEntityManager } from '@nestjs/typeorm'
import { EntityManager } from 'typeorm';
import { Repository, SelectQueryBuilder } from 'typeorm'
import { RoleEntity } from './entities/role.entity'
import { MenuService } from 'src/menu/menu.service'
import { CreateRoleDto } from './dto/create-role.dto'
import { UpdateRoleDto } from './dto/update-role.dto'
import { deepClone,compose } from '../utils/util'

@Injectable()
export class RoleService {
  constructor(
    @InjectRepository(RoleEntity)
    private readonly roleRepository: Repository<RoleEntity>,
    private readonly menuService: MenuService,
    @InjectEntityManager()
    private readonly entityManager: EntityManager
  ) { }

  // 创建角色
  async createRole(role: CreateRoleDto): Promise<RoleEntity | undefined> {
    // 先尝试根据名称查找角色
    const existingRole = await this.roleRepository.findOne({ where: { name: role.name } })
    if (existingRole) {
      throw new HttpException('角色已存在', HttpStatus.BAD_REQUEST)
    }
    let menu = []
    if (role.menus && role.menus.length > 0) {
      menu = await this.menuService.getMenusByIds(role.menus)
    }
    const roleParam: Partial<RoleEntity> = {
      ...role,
      menus: menu
    }
    const newRole = this.roleRepository.create(roleParam)
    return this.roleRepository.save(newRole)
  }

  //根据ids 获取角色
  async getRolesByIds(roleIds: (string | number)[]): Promise<RoleEntity[]> {
    const queryBuilder: SelectQueryBuilder<RoleEntity> = this.roleRepository.createQueryBuilder('role')
    return await queryBuilder.where('role.id IN (:...ids)', { ids: roleIds }).getMany()
  }

  //获取所有角色
  async getRoleList() {
    let roleList = await this.roleRepository.find()
    let result = roleList.filter(item => item.name != 'admin')
    return result
  }


  //获取 角色的菜单
  async getRoleMenus(id) {
    let roleData = await this.roleRepository.findOne({ where: { id: id }, relations: ['menus', 'menus.children', 'users'] });
    let copyMenu = deepClone(roleData.menus)
    copyMenu.forEach((item) => {
      if (item.first_menu) {
        copyMenu = compose(item, copyMenu)
      }

    })
    return copyMenu

    // let result = roleData.menus.map(item => {
    //   if (!item.parent) {
    //     return item
    //   }
    // })

    // return result
  }

  //修改角色
  async update(updateRoleDto: UpdateRoleDto) {
    const { id } = updateRoleDto;
    const role = await this.roleRepository.findOne({ where: { id } });
    if (!role) throw new Error('角色不存在')
    if (updateRoleDto.menus && updateRoleDto.menus.length > 0) {
      let menuEntities = await this.menuService.getMenusByIds(updateRoleDto.menus)
      role.menus = menuEntities
      delete updateRoleDto.menus
    }
    delete updateRoleDto.id
    Object.assign(role, updateRoleDto)
    return await this.roleRepository.save(role);
  }

  //删除角色

  // remove() 方法：
  // 通常用于实体（Entity）管理，适用于具有对象关系映射（ORM）的对象。
  // 当你调用 repository.remove(entity) 时，TypeORM 不仅会从数据库中删除该实体，还会触发实体上的所有预删除生命周期钩子（如 @BeforeRemove()），并处理关联表中的级联删除（如果已经在实体上配置了级联选项）。
  // 使用 remove() 删除实体时，TypeORM 会维护实体的状态，并且可能会对其他关联实体产生影响，比如多对一、一对多或多对多关系中的关联记录。

  // delete() 方法：
  // TypeORM 的 createQueryBuilder().delete() 或者 repository.delete() 提供了一种更灵活的方式来执行删除操作，它允许使用查询构建器（QueryBuilder）来指定删除条件，而不仅仅针对单个实体实例。
  // delete() 方法可以基于任意条件删除数据库中的行，而无需首先获取完整的实体实例。这在批量删除或者不需要实体实例的情况下更为高效。
  // 使用 delete() 方法时，不会触发实体的生命周期钩子，因为它不是基于实体实例进行的操作。

  async removeRole(id: number) {
    //第一种方式 通过entityManager来处理关系表

    // const rawSql = 'DELETE FROM user_roles WHERE roleId = ?';
    // await this.entityManager.query(rawSql,[id]);
    // return this.roleRepository.delete(id);

    // const role = await this.roleRepository.find({ where: { id: id + '' }, relations: ['users'] });
    //关系表 谁在前面就会有级联
    //所以删除role，role_menus 会更新
    //use_roles 要手动处理赋空
    // if (role.length != 0 && role[0]) {
    //   const roleParam: Partial<RoleEntity> = {
    //     ...role[0],
    //     users: []  // 清空角色的用户列表
    //   }
    //   // 保存更新的角色，这将触发中间表关系的更新
    //   await this.roleRepository.save(roleParam);
    //   // 删除角色
    //   await this.roleRepository.delete(id);
    //   return {}
    // }
    const role = await this.roleRepository.findOne({ where: { id: '' + id } })
    if (role) {
      await this.roleRepository.remove(role);
      return {}
    } else {
      throw new NotFoundException(`Role with ID ${id} not found.`)
    }

  }
}
